/**
 * 
 * @param {PixelBannerOptions} options
 * @returns {PixelBanner}
 */
function PixelBanner(options) {
      var opt = options;

      this.init = function() {
            if (opt.supportCanvas) {
                  // Rendering the modified versions of the images:
                  var canvas = document.createElement('canvas');
                  opt.context = canvas.getContext("2d");

                  // Make it the same size as the image
                  canvas.width = window.slides.img.width;
                  canvas.height = window.slides.img.height;

                  // Drawing the default version of the image on the canvas:
                  opt.context.drawImage(opt.img, 0, 0);
                  // Inserting the canvas in the DOM, before the image:

                  opt.img.parentNode.insertBefore(canvas, opt.img);
            }

            $(opt.prev).click(go);
            $(opt.next).click(go);


            opt.interval = window.setInterval(function() {
                  $(opt.prev).click();
            }, opt.interval);
      };

      var go = function() {
            //Reset the auto rotation.
            clearInterval(opt.interval);
            opt.interval = window.setInterval(function() {
                  $(opt.prev).click();
            }, opt.interval);

            if (opt.reset === opt.duration) {
                  var target = opt.target.eq(opt.current);
                  var nextIndex = 0;

                  // Depending on whether this is the next or previous
                  // arrow, calculate the index of the next slide accordingly.

                  if ($(this)[0] === $(opt.prev)[0]) {
                        nextIndex = opt.current >= opt.target.length - 1 ? 0 : opt.current + 1;
                  }
                  else {
                        nextIndex = opt.current <= 0 ? opt.target.length - 1 : opt.current - 1;
                  }

                  var next = opt.target.eq(nextIndex);

                  if (opt.supportCanvas) {
                        opt.img = next.find('img')[0];
                        applyPixelEffect();
                  }
                  else {
                        // This browser does not support canvas.
                        // Use the plain version of the slideshow.
                        next.addClass('slideActive').show();
                        target.removeClass('slideActive').hide();
                  }
                  opt.current = nextIndex;
            }
      };

      var apply = function() {
            opt.context.drawImage(opt.img, 0, 0);

            var pixelation = opt.duration;
            var sourceWidth = opt.img.width;
            var sourceHeight = opt.img.height;
            var imageData = opt.context.getImageData(0, 0, sourceWidth, sourceHeight);
            var data = imageData.data;

            var rgb = [0, 0, 0];
            var delta = 0;

            for (var y = 0; y < sourceHeight; y += pixelation) {
                  for (var x = 0; x < sourceWidth; x += pixelation) {
                        delta = ((sourceWidth * y) + x) * 4;
                        rgb[0] = data[delta];
                        rgb[1] = data[delta + 1];
                        rgb[2] = data[delta + 2];

                        for (var n = 0; n < pixelation; n++) {
                              for (var m = 0; m < pixelation; m++) {
                                    if (x + m < sourceWidth) {
                                          delta = ((sourceWidth * (y + n)) + (x + m)) * 4;
                                          data[delta] = rgb[0];
                                          data[delta + 1] = rgb[1];
                                          data[delta + 2] = rgb[2];
                                    }
                              }
                        }
                  }
            }

            // overwrite original image
            opt.context.putImageData(imageData, 0, 0);

            if (pixelation > 1) {
                  opt.duration = pixelation - 1;
                  window.requestAnimationFrame(applyPixelEffect);
            } else {
                  opt.duration = opt.reset;
            }
      };
}

function PixelBannerOptions(target, duration, interval, prev, next) {
      this.target = target;
      this.prev = prev;
      this.next = next;
      this.duration = duration;
      this.interval = interval;
      this.current = 0;
      this.context = undefined;
      this.reset = duration;
      this.intervalId = undefined;
      this.img = undefined;
      this.suportCanvas = 'getContext' in document.createElement('canvas');
}